64장. Read Replica — 읽기를 어떻게 늘릴까
이 장에서 말하고자 하는 것
Multi-AZ는 장애 대비를 해준다.
하지만 읽기 트래픽이 늘어나는 문제는 풀어주지 않는다.
사용자 늘어남
→ 읽기 쿼리 폭증
→ Primary DB CPU 100%
이때 등장하는 게
Read Replica
다.
1. Read Replica의 구조
[Primary] ← 쓰기
↓ 비동기 복제
[Replica 1] ← 읽기
[Replica 2] ← 읽기
[Replica 3] ← 읽기
- 쓰기는 Primary로
- 읽기는 Primary 또는 Replica로 분산
복제는 비동기 다.
Multi-AZ Standby가 동기인 것과 결정적으로 다르다.
2. Replication Lag — 약간의 지연
비동기 복제이므로 Replica는
항상 Primary보다 약간 뒤처질 수 있다
지연은 보통 수십 ms ~ 수 초 정도.
1. 사용자가 주문을 만든다 (Primary에 INSERT)
2. 곧장 "내 주문 목록" 요청 (Replica에서 SELECT)
3. Replica에 아직 반영 안 됨 → 새 주문이 안 보임
이 한 줄짜리 시나리오가 운영에서 자주 만난다.
3. 어떻게 다루는가
1. 강한 일관성이 필요한 읽기는 Primary로
주문 직후 사용자에게 보여줄 데이터 → Primary
대시보드 / 통계 / 검색 → Replica
2. 같은 트랜잭션 안에서는 같은 노드
쓰기 직후 같은 트랜잭션의 후속 읽기는 Primary로.
3. “내 데이터” 는 Primary로
자기가 방금 만든 데이터를 즉시 봐야 하는 화면은 Primary.
4. Read Replica 활용 패턴
| 패턴 | 용도 |
|---|---|
| 대시보드 / 분석 쿼리 | 무거운 SELECT 를 Replica로 격리 |
| 검색 / 통계 | 약간 오래된 데이터로도 충분 |
| Read-Heavy API | 다수의 Replica 로 수평 확장 |
| 다른 리전 Replica | DR · 글로벌 응답성 |
5. Cross-Region Read Replica
다른 리전에도 Replica를 둘 수 있다.
[ap-northeast-2: Primary]
↓ 리전 간 복제
[us-east-1: Replica]
용도:
- 글로벌 사용자에게 가까운 곳에서 읽기 응답
- DR (장애 복구) — 리전 전체 장애에 대비
6. Replica 승격 (Promotion)
Primary에 문제가 생기면 Read Replica를 승격(promote) 해 새 Primary로 만들 수 있다.
aws rds promote-read-replica \
--db-instance-identifier orders-replica-1
승격 후에는 더 이상 Replica가 아니다 (독립적인 DB).
7. 우리 서비스에서
[ECS "orders"]
↓ 쓰기·강한 읽기
[RDS Primary (Multi-AZ)]
↓ 비동기 복제
[Replica 1] ← 무거운 SELECT
[Replica 2] ← 대시보드
- Primary: 트랜잭션 · 강한 일관성 읽기
- Replicas: 대시보드 · 통계 · 무거운 SELECT
읽기 쿼리가 한가하면 Replica는 0~1개로 시작.
8. 직접 확인해보기 — CLI
Read Replica 만들기
aws rds create-db-instance-read-replica \
--db-instance-identifier orders-replica-1 \
--source-db-instance-identifier orders \
--db-instance-class db.t4g.small
Replication Lag 확인
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name ReplicaLag \
--dimensions Name=DBInstanceIdentifier,Value=orders-replica-1 \
--start-time 2026-01-01T00:00:00Z \
--end-time 2026-01-02T00:00:00Z \
--period 60 \
--statistics Average
ReplicaLag 알람은 거의 항상 켠다
9. 코드로는 이렇게 생겼다 — Terraform
resource "aws_db_instance" "orders" {
identifier = "orders"
engine = "postgres"
instance_class = "db.t4g.small"
multi_az = true
# ... 62장 코드와 동일
}
resource "aws_db_instance" "orders_ro" {
identifier = "orders-ro-1"
replicate_source_db = aws_db_instance.orders.identifier
instance_class = "db.t4g.small"
publicly_accessible = false
vpc_security_group_ids = [aws_security_group.db.id]
}
Replica는 별도 엔드포인트를 가진다.
10. 애플리케이션에서 두 엔드포인트 다루기
DATABASE_URL=postgres://...primary.../app
DATABASE_RO_URL=postgres://...replica.../app
코드에서
if (isReadOnly && !needsStrongConsistency) → DATABASE_RO_URL
else → DATABASE_URL
ORM에 따라 read/write 분리를 자동화해주는 기능이 있다.
11. 이렇게 쓰면 망한다 — 안티패턴
안티패턴 1. 강한 일관성이 필요한 읽기를 Replica로 보낸다
“방금 만든 데이터가 안 보이는” 버그가 난다.
안티패턴 2. ReplicaLag 알람을 안 건다
복제가 끊겼는데도 모른다 → Replica에서 옛 데이터만 응답.
안티패턴 3. Replica 한 대로 모든 읽기를 받는다
Replica가 죽으면 즉시 부하가 Primary로 몰린다.
운영 부하가 크다면 Replica도 2대 이상
안티패턴 4. Replica를 영원한 DR 백업으로만 둔다
DR이 목적이라면 Cross-Region Replica + 정기 페일오버 시험이 필요하다.
승격 절차를 한 번도 안 해봤다면 실전에서 실패한다.
12. 한 줄로 정리
Read Replica는 비동기 복제 기반으로 읽기 부하를 분산하는 도구이며,
강한 일관성이 필요한 읽기와 그렇지 않은 읽기를 구분하는 게 핵심이다
13. 이 장의 핵심 정리
- Read Replica는 비동기 복제 기반의 읽기 전용 DB다.
- Multi-AZ Standby와는 다르다 — Standby는 트래픽을 안 받는다.
- Replication Lag 때문에 강한 일관성 읽기는 Primary로 보낸다.
- Cross-Region Replica로 글로벌 응답성과 DR을 동시에 다룰 수 있다.
- ReplicaLag 알람은 거의 항상 켠다.
- 승격 절차는 사전에 시뮬레이션해 둔다.